'''localvalidator is a lightweight approach for performing a local validation in an easy way

:Date: 2009-04-21
:Author: Rodrigo Manhaes 
'''

import re

class ValidationError(Exception):
    '''Standard exception class for localvalidator'''
    pass

DEFAULT_VALIDATION_CLASS = ValidationError

class LocalValidationCase:
    '''Represents a validation case, which has the success condition, 
    the error message and the class of exception which will be thrown 
    case validation fails.
    '''
    def __init__(self, success_condition, exception_message=None, exception_class=DEFAULT_VALIDATION_CLASS):
        self.success_condition = success_condition
        self.exception_message = exception_message
        self.exception_class = exception_class
    
    def is_valid(self):
        '''Checks validation case for success'''
        return self.success_condition


class LocalValidationContext:
    '''Represents a validation context.
    Once created, several validation cases can be added to context. These validations
    will be performed just after the validation method be called
    '''
    def __init__(self, validation_cases=None):
        if validation_cases:
            self.validation_cases = validation_cases
        else:
            self.validation_cases = []
        
    def add_valid_condition(self, condition, exception_message=None, 
                            exception_class=DEFAULT_VALIDATION_CLASS):
        '''Adds a valid condition to be checked'''
        self.validation_cases.append(
             LocalValidationCase(condition, exception_message, exception_class))
        return self
        
    def add_invalid_condition(self, condition, exception_message=None, 
                              exception_class=DEFAULT_VALIDATION_CLASS):
        '''Adds an invalid condition to be checked'''
        self.validation_cases.append(
             LocalValidationCase(not condition, exception_message, exception_class))
        return self
        
    def add_not_none_checking(self, object, exception_message=None, 
                              exception_class=DEFAULT_VALIDATION_CLASS):
        '''Adds not none checking for a given object'''
        self.validation_cases.append(
             LocalValidationCase(object is not None, exception_message, exception_class))
        return self
    
    def add_none_checking(self, object, exception_message=None, 
                          exception_class=DEFAULT_VALIDATION_CLASS):
        '''Adds none checking for a given object'''
        self.validation_cases.append(
             LocalValidationCase(object is None,exception_message, exception_class))
        return self
    
    def add_non_empty_checking(self, object, exception_message=None, 
                               exception_class=DEFAULT_VALIDATION_CLASS,  
                               consider_spaces=True):
        '''Adds non empty checking for a given object. It checks if object is not null and
        its length is greater than zero.
        space_matters param informs if whitespace is relevant
        '''
        if object and object.__class__ == str and not consider_spaces:
            object = object.strip()
        self.validation_cases.append(
             LocalValidationCase(object is not None and len(object) > 0, exception_message, exception_class))
        return self
    
    def add_equals_checking(self, object1, object2, exception_message=None, 
                            exception_class=DEFAULT_VALIDATION_CLASS):
        '''Add equals checking for a given object pair'''
        self.validation_cases.append(
             LocalValidationCase(object1 == object2, exception_message, exception_class))
        return self
    
    def add_not_equals_checking(self, object1, object2, exception_message=None, 
                            exception_class=DEFAULT_VALIDATION_CLASS):
        '''Add not equals checking for a given object pair'''
        self.validation_cases.append(
             LocalValidationCase(object1 != object2, exception_message, exception_class))
        return self
    
    def add_custom_validation(self, validate_object, exception_message=None, 
                              exception_class=DEFAULT_VALIDATION_CLASS):
        '''Adds a given custom validator. The validator object must be a validate() method'''
        self.validation_cases.append(
             LocalValidationCase(validate_object.validate(), 
                                 exception_message,exception_class))
        return self
    
    def add_matching_checking(self, value, regex, exception_message=None, 
                           exception_class=DEFAULT_VALIDATION_CLASS):
        '''Adds checking for regular expression matching'''
        self.validation_cases.append(
             LocalValidationCase(re.match(regex, value), exception_message, exception_class))
        return self
    
    def clear(self):
        '''Clears the context'''
        self.validation_cases = []
        self.exception_class = DEFAULT_VALIDATION_CLASS
        return self 
    
    def validate(self):
        '''Checks the validation cases and throws the required exception
        when the first invalid case is found. 
        '''
        count = 1
        for validation_case in self.validation_cases:
            if not validation_case.is_valid():
                msg = validation_case.exception_message 
                message = msg if msg else 'Validation error [%d]' % count
                raise validation_case.exception_class, message
            count += 1